#include<iostream>
#include<string>
#include<vector>
#include<boost/filesystem.hpp>
#include"util.hpp"

// 文件input中的所有网页
const std::string src_path("data/input/");
const std::string output("data/out.bin");

typedef struct DocInfo
{
    std::string title;  //标题
    std::string content;//正文内容
    std::string url;    //在原网页中的url
}DocInfo_t;

//const & 输入
//* 输出
//& 输入输出
bool EnumFiles(const std::string& src_path,std::vector<std::string>* files_list);
bool ParseHtml(const std::vector<std::string>& files_list,std::vector<DocInfo_t>* results);
bool SaveHtml(const std::vector<DocInfo_t>& results,const std::string& output);

//static 让函数只能在此文件中调用
static bool ParseTitle(const std::string& result,std::string* title)
{
    std::size_t start= result.find("<title>");
    std::size_t end= result.find("</title>");

    if(start == std::string::npos || end == std::string::npos || start > end)
    {
        return false;
    }

    start+=std::string("<title>").size();
    *title = result.substr(start,end-start);
    return true;
}

static bool ParseContent(const std::string& result,std::string* content)
{
    enum status
    {
        LABLE,
        CONTENT
    };

    enum status s = LABLE;

    for(char c: result)
    {
        switch(s)
        {
            case LABLE:
                if(c=='>')
                {
                    s=CONTENT;
                }
                break;
            case CONTENT:
                if(c=='<')
                {
                    s=LABLE;
                }
                else
                {
                    if(c=='\n') // 这里把\n删除，方便后续用\n作为文档之间的分隔符
                    {
                        c=' ';
                    }
                    content->push_back(c);
                }
                break;
        }
    }

    return true;
}

static bool ParseUrl(const std::string& file_path,std::string* src)
{
    std::string url_head = "https://www.boost.org/doc/libs/1_88_0/doc/html/";
    std::string url_tail = file_path.substr(src_path.size());
    *src = url_head + url_tail;

    return true;
}

int main()
{
    std::vector<std::string> files_list; //每个html文件的名字(带路径)
    std::vector<DocInfo_t> results;
    // 遍历每个文件,并将路径存储到files_list中
    if(!EnumFiles(src_path,&files_list))
    {
        std::cerr<<src_path<<"html文件遍历失败\n";
        return 1;
    }

    //解析每个html文件
    if(!ParseHtml(files_list,&results))
    {
        std::cerr<<"html文件解析失败\n";
        return 2;
    }

    //把解析结果放入output中
    if(!SaveHtml(results,output))
    {
        std::cerr<<"文件保存失败\n";
        return 3;
    }

    //执行了这句话，说明前面没有报错
    std::cout<<"初始化成功"<<std::endl;
    return 0;
}

bool EnumFiles(const std::string& src_path,std::vector<std::string>* files_list)
{
    //debug
    //int total=0;

    // 使用bf来代替boost::filesystem，简化后续代码
    namespace bf = boost::filesystem;

    //初始化路径，也就是定义递归的起点
    bf::path root_path(src_path); 

    // 对路径的合法性进行判断
    if(!bf::exists(root_path))
    {
        std::cerr<<src_path<<"路径不存在或不合法\n";
        return false;
    }

    //定义一个空的迭代器，用来判断迭代器是否递归结束
    bf::recursive_directory_iterator end;

    //使用迭代器递归查找所有的文件
    for(bf::recursive_directory_iterator iter(root_path);iter!=end;iter++)
    {
        //这里把非普通文件和普通文件中不是html为后缀的文件忽略
        if(!bf::is_regular_file(*iter) || iter->path().extension()!=".html")
        {
            continue;
        } 
        //debug
        //total++; 
        //std::cout<<"debug "<< iter->path().string() << std::endl;

        //用字符串的格式把路径存储入files_list方便后续处理
        files_list->push_back(iter->path().string());
    }

    //debug
    //std::cout<<total<<std::endl; 
    return true;
}

//debug
static void ShowDoc(const DocInfo_t& Doc)
{
    std::cout<<"标题:"<<Doc.title<<std::endl;
    std::cout<<"内容:"<<Doc.content<<std::endl;
    std::cout<<"网址:"<<Doc.url<<std::endl;
}

bool ParseHtml(const std::vector<std::string>& files_list,std::vector<DocInfo_t>* results)
{
    for(const auto& file_name:files_list)
    {
        std::string result;
        // 读取文件
        if(!us_util::FileUtil::ReadFile(file_name,&result))
        {
            continue;
        }

        DocInfo_t Doc;
        // 解析文件中的title内容
        if(!ParseTitle(result,&Doc.title))
        {
            continue;
        }
        // 解析文件中的正文内容。本质是去标签
        if(!ParseContent(result,&Doc.content))
        {
            continue;
        }
        // 解析文件，并构建URL
        if(!ParseUrl(file_name,&Doc.url))
        {
            continue;
        }

        // 到这里说明三个内容全部解析成功
        results->push_back(std::move(Doc));
        
        //debug代码
        // ShowDoc(Doc);
        // break;
    }

    return true;
}

bool SaveHtml(const std::vector<DocInfo_t>& results,const std::string& output)
{
    std::ofstream out(output,std::ios::out | std::ios::binary);
    const std::string SEP="\3"; // \3作为文档内容的分隔符，文档与文档之间使用\n分割

    for(const auto& Doc:results)
    {
        std::string s;
        s+=Doc.title;
        s+=SEP;
        s+=Doc.content;
        s+=SEP;
        s+=Doc.url;
        s+='\n';

        out.write(s.c_str(),s.size());
    }

    out.close();
    return true;
}